﻿#define  _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
//int main()
//{
//	int a[] = { 1,2,3,4 };
//	printf("%d\n", sizeof(a));//16;a是数组名，数组名单独放在sizeof中，数组名表示整个数组，
//	//计算的是整个数组的大小，单位是字节。
//	printf("%d\n", sizeof(a + 0));//4/8；a是数组名，没有单独放在sizeof内,也没有&，所以a就是首元素的地址
//	//a+0，还是首元素的地址，sizeof(a + 0)计算的是一个地址的大小，4/8
//	printf("%d\n", sizeof(*a));//4;a是数组名，没有单独放在sizeof内,也没有&，所以a就是首元素的地址
//	//*a就是首元素==a,就是整数1，sizeof(*a)就是4个字节
//	printf("%d\n", sizeof(a + 1));//4/8;a是首元素地址，a+1就是第二个元素的地址，sizeof(a+1)就是地址的大小
//	printf("%d\n", sizeof(a[1]));//4；a[1]就是数组第二个元素，大小是4个字节
//	printf("%d\n", sizeof(&a));//4/8；&a取出的是数组的地址，是地址，那大小就是4/8
//	//&a的特殊性在+-整数，int(*p)[4]=&a;每次跳过一个数组
//	printf("%d\n", sizeof(*&a));//16；&a-取出的是数组的地址，它的类型是int(*)[4]，对数组指针解引用，
//	//访问的是这个数组，大小就是16个字节
//	//也可以这样理解：*&a==a,sizeof(*&a)==sizeof(a);
//	printf("%d\n", sizeof(&a + 1));//4/8;&a是数组的地址，&a+1是跳过数组后的地址，是地址就是4/8个字节
//	printf("%d\n", sizeof(&a[0]));//4/8;a[0]是第一个元素，&a[0]就是第一个元素的地址，大小就是4/8
//	printf("%d\n", sizeof(&a[0] + 1));//4/8, &a[0]是第一个元素的地址，&a[0]+1就是第二个元素的地址
//
//	return 0;
//}

//int main()
//{
//	char arr[] = { 'a','b','c','d','e','f' };
//	printf("%d\n", sizeof(arr));//6;arr表示整个数组，sizeof(arr)计算的是整个数组的大小
//	printf("%d\n", sizeof(arr + 0));//4/8；arr是首元素的地址，只要是地址，就是4/8
//	printf("%d\n", sizeof(*arr));//1；arr是首元素的地址,*arr就是首元素，sizeof(*arr)计算的是首元素的大小
//	printf("%d\n", sizeof(arr[1]));//1
//	printf("%d\n", sizeof(&arr));//4/8；&arr取出的是数组的地址，数组的地址也是地址，大小就是4/8个字节
//	printf("%d\n", sizeof(&arr + 1));//4/8；&arr+1是跳过数组后的地址，跳过去后还是地址，大小就是4/8个字节
//	printf("%d\n", sizeof(&arr[0] + 1));//4/8；&arr[0] + 1是数组第二个元素的地址，大小就是4/8个字节
//
//	return 0;
//}

#include <string.h>
//int main()
//{
//	char arr[] = { 'a','b','c','d','e','f' };
//	printf("%zu\n", strlen(arr));//随机值，arr是数组首元素的地址，字符串中没有\0
//	printf("%zu\n", strlen(arr + 0));//随机值，arr+0还是首元素的地址，字符串中没有\0
//	//printf("%zu\n", strlen(*arr));//arr是数组首元素的地址,*arr是首元素-'a'-97
//	//非法访问内存，程序崩溃
//	printf("%zu\n", strlen(arr[1]));//非法访问内存，崩溃，arr[1] == 'b' == 98
//	printf("%zu\n", strlen(&arr));//随机值,&arr是数组的地址，字符串中没有\0
//	printf("%zu\n", strlen(&arr + 1));//随机值，&arr+1是跳过整个数组后的地址，向后找\0，也是随机值
//	printf("%zu\n", strlen(&arr[0] + 1));//随机值，&arr[0] + 1是第二个元素的地址
//	return 0;
//}

//int main()
//{
//    char arr[] = "abcdef";
//    printf("%zu\n", sizeof(arr));//7
//    printf("%zu\n", sizeof(arr + 0));//4/8
//    printf("%zu\n", sizeof(*arr));//1
//    printf("%zu\n", sizeof(arr[1]));//1
//    printf("%zu\n", sizeof(&arr));//4/8
//    printf("%zu\n", sizeof(&arr + 1));//4/8
//    printf("%zu\n", sizeof(&arr[0] + 1));//4/8
//    return 0;
//}

//int main()
//{
//    char arr[] = "abcdef";
//    printf("%zu\n", strlen(arr));//6
//    printf("%zu\n", strlen(arr + 0));//6
//    //printf("%zu\n", strlen(*arr));//err
//    //printf("%zu\n", strlen(arr[1]));//err
//    printf("%zu\n", strlen(&arr));//6
//    printf("%zu\n", strlen(&arr + 1));//随机值
//    printf("%zu\n", strlen(&arr[0] + 1));//5
//    return 0;
//}

//int main()
//{
//    char* p = "abcdef";//p指向首元素地址
//    printf("%zu\n", sizeof(p));//4/8, p是指针变量
//    printf("%zu\n", sizeof(p + 1));//4/8, p+1就是b的地址
//    printf("%zu\n", sizeof(*p));//1
//    printf("%zu\n", sizeof(p[0]));//1, p[0]->*(p+0) -> *p
//    printf("%zu\n", sizeof(&p));//4/8, &p是指针变量p的地址，是一个二级指针
//    printf("%zu\n", sizeof(&p + 1));//4/8
//    printf("%zu\n", sizeof(&p[0] + 1));//4/8, &p[0] + 1是b的地址
//    return 0;
//}

//int main()
//{
//    int a[3][4] = { 0 };
//    printf("%zu\n", sizeof(a));//48;4*12
//    printf("%zu\n", sizeof(a[0][0]));//4
//    printf("%zu\n", sizeof(a[0]));//16,a[0]是第一行这个一维数组的数组名，单独放在sizeof内部，表示第一行数组
//    //sizeof(a[0])计算的是第一行的大小
//    printf("%zu\n", sizeof(a[0] + 1));//4/8, a[0]就是第一行第一个元素的地址&a[0][0], a[0]+1是第一行第二个元素的地址
//    printf("%zu\n", sizeof(*(a[0] + 1)));//4, *(a[0] + 1)是第一行第二个元素
//    printf("%zu\n", sizeof(a + 1));//4/8, a是二维数组的数组名，表示数组首元素的地址，也就是第一行的地址
//    //a+1 就是第二行的地址
//    //a --> int(*)[4]
//    printf("%zu\n", sizeof(*(a + 1)));//16，*(a + 1) == a[1],a[1]就是第2行的数组名，计算的是整个数组的大小
//    printf("%zu\n", sizeof(&a[0] + 1));//4/8
//    //a[0]是第一行的数组名
//    //&a[0]取出的是第1行的地址
//    //&a[0] + 1是第2行的地址
//    printf("%zu\n", sizeof(*(&a[0] + 1)));//16
//    printf("%zu\n", sizeof(*a));//16，a是二维数组的数组名，这里只能表示数组首元素的地址，也就是第一行的地址
//    //*a 就是第一行
//    printf("%zu\n", sizeof(a[3]));//16，不会有越界访问
//    //sizeof在计算变量，数组的大小的时候，是通过类型来推导的，不会真实去访问内存空间
//
//    return 0;
//}

//int main()
//{
//	short s = 4;//short-2字节
//	int a = 10;
//	printf("%zu\n", sizeof(s = a + 2));//2
//	//                 short  int  int
//	printf("s = %hd\n", s);//4
//	return 0;
//}

//int main()
//{
//    int a[5] = { 1, 2, 3, 4, 5 };
//
//    int* ptr = (int*)(&a + 1);
//    printf("%d, %d", *(a + 1), *(ptr - 1));//2  5
//
//    return 0;
//}

//在X86环境下 假设结构体的⼤⼩是20个字节 
//程序输出的结果是什么？ 
//struct Test
//{
//	int Num;
//	char* pcName;
//	short sDate;
//	char cha[2];
//	short sBa[4];
//}*p = (struct Test*)0x100000;
//int main()
//{
//	printf("%p\n", p + 0x1);//20个字节，16进制为14字节，0x100014
//	printf("%p\n", (unsigned long)p + 0x1);//整数+1，0x100001
//	printf("%p\n", (unsigned int*)p + 0x1);//无符号整型+1整型，0x100004
//	return 0;
//}


//int main()
//{
//    int a[3][2] = { (0, 1), (2, 3), (4, 5) };//这是逗号表达式
//    //                 1       3       5
//    int* p;
//    p = a[0];//&a[0][0];
//    printf("%d", p[0]);//1；(*p+0)
//    return 0;
//}

//int main()
//{
//	int aa[2][5] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
//	int* ptr1 = (int*)(&aa + 1);
//	int* ptr2 = (int*)(*(aa + 1));
//	printf("%d,%d", *(ptr1 - 1), *(ptr2 - 1));//10,5
//	return 0;
//}


////假设环境是x86环境
//int main()
//{
//	int a[5][5];
//	int(*p)[4];
//	p = a;
//	printf("%p,%d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);//小地址-大地址=负数
//	//随着数组下标的增长，地址是由低到高变化的
//	//%d-按照10进制的形式，打印有符号的整数
//	//%d认为内存中存放的是有符号整数的补码
//	//%p-打印地址，以十六进制打印
//	//-4
//    //10000000 00000000 00000000 00000100
//    //11111111 11111111 11111111 11111011
//    //11111111 11111111 11111111 11111100
//    //FF       FF       FF       FC
//	return 0;
//}

//int main()
//{
//	char* a[] = { "work","at","alibaba" };
//	char** pa = a;
//	pa++;
//	printf("%s\n", *pa);//at
//	return 0;
//}

//int main()
//{
//	char* c[] = { "ENTER","NEW","POINT","FIRST" };
//	char** cp[] = { c + 3,c + 2,c + 1,c };
//	char*** cpp = cp;
//	printf("%s\n", **++cpp);//原本指向c+3，++后指向c+2，打印point
//	printf("%s\n", *-- * ++cpp + 3);//在上述++cpp基础上再++，指向new,又--，指向enter,又+3,打印er
//	printf("%s\n", *cpp[-2] + 3);//**(cpp-2)+3，其中cpp-2减去前两步+2,则指向c+3,解引用后为first,又+3,打印st
//	printf("%s\n", cpp[-1][-1] + 1);//*(*(cpp-1)-1)+1,本来是cpp+2,-1后指向point,又-1,指向new,+1,打印ew
//	return 0;
//}
